﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KZ400B
{
    public class UnpacketResult
    {
        public UnpacketResult()
        {
            m_result = false;
            m_commFlag = KZ400B.CommFlag.Empty;
            m_functionCode = KZ400B.FunctionCode.Empty;
            m_content = string.Empty;
        }

        private bool m_result;

        public bool Result
        {
            get { return m_result; }
            set { m_result = value; }
        }

        private string m_commFlag;

        public string CommFlag
        {
            get { return m_commFlag; }
            set { m_commFlag = value; }
        }

        private string m_functionCode;

        public string FunctionCode
        {
            get { return m_functionCode; }
            set { m_functionCode = value; }
        }
        private string m_content;

        public string Content
        {
            get { return m_content; }
            set { m_content = value; }
        }

        public bool Approximate( UnpacketResult r)
        {
            //if (l == null && r == null) return true;
            //else if (l == null && r != null) return false;
             if (r == null) return false;

             return this.m_result == r.m_result
                 && this.m_commFlag == r.m_commFlag
                 && (string.IsNullOrEmpty(r.m_functionCode) 
                        || this.m_functionCode == r.m_functionCode)
                && this.m_content.IndexOf( r.m_content) >= 0;
        }

        public bool UnApproximate ( UnpacketResult r)
        {
            //if (l == null && r == null) return false;
            //else if (l == null && r != null) return true;
            // if (r == null) return true;

            //return this.m_result != r.m_result
            //    || this.m_commFlag != r.m_commFlag
            //    || this.m_functionCode != r.m_functionCode
            //    || this.m_content.IndexOf( r.m_content) < 0;

            return !Approximate(r);
        }
    }

    public class Protocol
    {
        public static string getVerify(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                throw new Exception("传入数据不能为空");
            }
            StringBuilder contBd = new StringBuilder();
            byte vC1 = 0x00;
            byte vC2 = 0x00;
            if (
                Verify.Compute(data
                            , ref vC1
                            , ref vC2)
                    == ErrorCode.Success
                )
            {
                contBd.Append((char)vC1);
                contBd.Append((char)vC2);
            }
            return contBd.ToString();
        }
        public static string getVerifyAndEndFlag(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                throw new Exception("传入数据不能为空");
            }
            StringBuilder contBd = new StringBuilder();
            contBd.Append(getVerify(data));
            contBd.Append(CommFlag.SingleEnd);
            return contBd.ToString();
        }

        public static string getACKString()
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Response);
            contBd.Append("OK");
            string strSuffix = getVerify(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        public static string getNACKString()
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Response);
            contBd.Append("ERR");
            string strSuffix = getVerify(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }


        /// <summary>
        /// 联络指令
        /// </summary>
        /// <returns></returns>
        public static string GetContactString() 
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Contact);
            contBd.Append(FunctionCode.Contact);
            contBd.Append(CommFlag.Query);
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            //contBd.Append(CommFlag.AllEnd);
            return contBd.ToString();
        }

        /// <summary>
        /// 基本运行参数设置指令 
        /// </summary>
        /// <returns></returns>
        public static string GetParameterSettingString(
            string axleName
             , Axle.Direction dir
            , double period 
            ,double totalStep
         )
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.ParameterSetting);
            contBd.Append(FunctionCode.ParameterSetting);
            contBd.Append(axleName);
            contBd.Append(CommFlag.Space);
            //contBd.Append(CommFlag.Space);
            contBd.Append(dir.ToString());
            contBd.Append(CommFlag.Separate);
            contBd.Append(Axle.RunningPeriodConverter.GetRunningPeriod(period));
            contBd.Append(CommFlag.Separate);
            //contBd.Append(CommFlag.Space);
            contBd.Append(Axle.TargetStepConverter.GetTargetStep(totalStep));

            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 加速度参数设置
        /// </summary>
        /// <param name="axleName"></param>
        /// <param name="aLevel"></param>
        /// <returns></returns>
        public static string GetAccelerationSettingString(string axleName, Axle.AccelerationLevel aLevel)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.AccelerationSetting);
            contBd.Append(FunctionCode.AccelerationSetting);
            contBd.Append(axleName);
            contBd.Append(CommFlag.Space);
            contBd.Append(aLevel.ToString());
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 运行指令(单轴)
        /// </summary>
        /// <param name="axleNameList"></param>
        /// <returns></returns>
        public static string GetRunString(string axleName)
        {
            List<string> axleNameList = new List<string>();
            axleNameList.Add(axleName);
            return GetRunString(axleNameList);
        }

        /// <summary>
        /// 运行指令(多轴)
        /// </summary>
        /// <param name="axleNameList"></param>
        /// <param name="isAll"></param>
        /// <returns></returns>
        public static string GetRunString(List<string> axleNameList)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Run);
            contBd.Append(FunctionCode.Run);
            if (axleNameList != null)
            {
                foreach (string axleName in axleNameList)
                {
                    contBd.Append(axleName);
                }
            }
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }


        /// <summary>
        /// 停止指令(单轴)
        /// </summary>
        /// <param name="axleNameList"></param>
        /// <returns></returns>
        public static string GetStopString(string axleName)
        {
            List<string> axleNameList = new List<string>();
            axleNameList.Add(axleName);
            return GetStopString(axleNameList);
        }

        /// <summary>
        /// 停止指令(多轴)
        /// </summary>
        /// <param name="axleNameList"></param>
        /// <param name="isAll"></param>
        /// <returns></returns>
        public static string GetStopString(List<string> axleNameList)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Stop);
            contBd.Append(FunctionCode.Stop);
            if (axleNameList != null)
            {
                foreach (string axleName in axleNameList)
                {
                    contBd.Append(axleName);
                }
            }
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 归零指令 
        /// </summary>
        /// <param name="axleName"></param>
        /// <returns></returns>
        public static string GetToZeroString(string axleName,double period)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.ToZero);
            contBd.Append(FunctionCode.ToZero);
            contBd.Append(axleName);
            contBd.Append(CommFlag.Space);
            contBd.Append(((int)period).ToString());
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 查询当前位置
        /// </summary>
        /// <param name="alxeName"></param>
        /// <returns></returns>
        public static string GetQueryPostionString(string axleName)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Query);
            contBd.Append(axleName);
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 查询指令是否成功
        /// </summary>
        /// <param name="alxeName"></param>
        /// <returns></returns>
        public static string GetQuerySuccessString()
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.Query);
            contBd.Append(FunctionCode.QuerySuccess);
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 相对零位设置
        /// </summary>
        /// <param name="axleName"></param>
        /// <returns></returns>
        public static string GetRelativeZeroString(string axleName)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.RelativeZero);
            contBd.Append(FunctionCode.RelativeZero);
            contBd.Append(axleName);
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 细分参数设置
        /// </summary>
        /// <param name="axleName"></param>
        /// <param name="sValue"></param>
        /// <returns></returns>
        public static string GetStepperAngleFraction(string axleName, int sValue)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.StepperAngleFraction);
            contBd.Append(FunctionCode.StepperAngleFraction);
            contBd.Append(axleName);
            contBd.Append(CommFlag.Space);
            contBd.Append(sValue.ToString());
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 参数保留
        /// </summary>
        /// <param name="axleName"></param>
        /// <param name="sValue"></param>
        /// <returns></returns>
        public static string GetParameterPreserve()
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.ParameterPreserve);
            contBd.Append(FunctionCode.ParameterPreserve);
            contBd.Append(Axle.AllAxleName);
            contBd.Append(CommFlag.Space);
            contBd.Append("S");
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        /// <summary>
        /// 虚拟零位
        /// </summary>
        /// <param name="axleName"></param>
        /// <param name="sValue"></param>
        /// <returns></returns>
        public static string GetVZero(string axleName)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(CommFlag.VZero);
            contBd.Append(FunctionCode.VZero);
            contBd.Append(axleName);
            string strSuffix = getVerifyAndEndFlag(contBd.ToString());
            contBd.Append(strSuffix);
            return contBd.ToString();
        }

        public static string Packet(string data)
        {
            StringBuilder contBd = new StringBuilder();
            contBd.Append(data);
            contBd.Append(CommFlag.AllEnd);
            return contBd.ToString();
        }

        public static UnpacketResult Unpack(string data)
        {
            UnpacketResult rst = new UnpacketResult();
            if (!data.StartsWith(CommFlag.Response) || !data.EndsWith(CommFlag.AllEnd))
            {
                Console.WriteLine("Syntax ERROR");
                return rst;
            }
            string tmpString = data.TrimEnd(CommFlag.AllEnd[0]);
            StringBuilder sComm = new StringBuilder();
            byte vCode1 = 0;
            byte vCode2 = 0;
            if (tmpString.Length > 2)
            {
                for (int i = 0; i < tmpString.Length - 2; i++)
                {
                    sComm.Append(tmpString[i]);
                }
                vCode1 = (byte)tmpString[tmpString.Length - 2];
                vCode2 = (byte)tmpString[tmpString.Length - 1];
            }
            string commString = sComm.ToString();
            if (!Verify.IsVerify(commString, vCode1, vCode2))
            {
                rst.Result = false;
                return rst;
                //throw new Exception("校验错误");
            }

            if (!string.IsNullOrEmpty(commString) && commString.Length > 2)
            {
                rst.Result = true;
                rst.CommFlag = commString[1].ToString();
                int offset = 3;
                if (rst.CommFlag.Equals(CommFlag.Query))
                {
                    if (commString[2].ToString().Equals(FunctionCode.QuerySuccess))
                    {
                        rst.FunctionCode = FunctionCode.QuerySuccess;
                    }
                    else
                    {
                        rst.FunctionCode = FunctionCode.Query;
                        offset = 2;
                    }
                }
                else
                {
                    rst.FunctionCode = commString[2].ToString();
                }
                rst.Content = commString.Substring(offset);
            }
            
            return rst;
        }

        public static AxleAction UnpackAction(string data)
        {
            AxleAction action = new AxleAction();
            if (string.IsNullOrEmpty(data) 
                || data.IndexOf(":") <= 0 
                || !data.EndsWith(CommFlag.AllEnd)
                )
            {
                Console.WriteLine("NO DATA OR DATA ERROR");
                return action;
            }
            if (!data.StartsWith(CommFlag.Response))
            {
                Console.WriteLine("Syntax ERROR");
                return action;
            }

            //verify
            string tmpString = data.TrimEnd(' ').TrimEnd(CommFlag.AllEnd[0]);
            StringBuilder sComm = new StringBuilder();
            byte vCode1 = 0;
            byte vCode2 = 0;
            if (tmpString.Length > 2)
            {
                for (int i = 0; i < tmpString.Length - 2; i++)
                {
                    sComm.Append(tmpString[i]);
                }
                vCode1 = (byte)tmpString[tmpString.Length - 2];
                vCode2 = (byte)tmpString[tmpString.Length - 1];
            }
            string commString = sComm.ToString();
            if (!Verify.IsVerify(commString, vCode1, vCode2))
            {
                throw new Exception("校验错误");
            }

            int offset = 0;
            if (data[offset++] == CommFlag.Response[0])
            {
                string fCode = data[offset++].ToString();
                string funCode = data[offset++].ToString();
                if(fCode.Equals(CommFlag.Run))
                {
                    if (funCode.Equals(FunctionCode.Run))
                    {
                        action.Action = AxleActions.RunFinish;
                    }
                    else
                    {
                        throw new Exception("功能码不匹配错误");
                    }
                }
                else if (fCode.Equals(CommFlag.Stop))
                {
                    if (funCode.Equals(FunctionCode.Stop))
                    {
                        action.Action = AxleActions.StopFinish;
                    }
                    else
                    {
                        throw new Exception("功能码不匹配错误");
                    }
                }
                else if (fCode.Equals(CommFlag.ToZero))
                {
                    if (funCode.Equals(FunctionCode.ToZero))
                    {
                        action.Action = AxleActions.ToZeroFinish;
                    }
                    else
                    {
                        throw new Exception("功能码不匹配错误");
                    }
                }
                else
                {
                    throw new Exception("功能码错误");
                }

                //axle list
                string[] sqs = data.Split(':');
                string axleList = sqs[0].Substring(offset);
                if (!string.IsNullOrEmpty(axleList))
                { 
                    char[] axs = axleList.ToCharArray();
                    foreach(char ax in axs)
                    {
                        action.Add(ax.ToString());
                    }
                }
                if (sqs[1].IndexOf("OK") >= 0)
                {
                    action.Result = true;
                }
                else if (sqs[1].IndexOf("ERR") >= 0)
                {
                    action.Result = false;
                }
            }
            return action;
        }

    }
}
